visibility

__attribute__((visibility("visibility_type")))
当我们并不希望暴露一个方法时,一般情况使用static关键字来修饰函数。这样编译时该方法就不会被输出到符号表里。详细可参见这篇博文

LLVM和GCC其实也提供了类似的attribute

使用示例:

__attribute__((visibility("default"))) void foo1(int x, int y);
__attribute__((visibility("hidden"))) int foo2(int x);
__attribute__((visibility("protected"))) void foo3(int x, int y);
  • default意味着该方法对其他模块是可见的。

  • hidden表明该方法符号不会被放到动态符号表里,所以其他模块(可执行文件或者动态库)不可以通过符号表访问该方法。(但在运行时使用函数指针可对其进行调用,visibility是个编译时的特性,正如你在运行时可以修改const修饰的变量一样)

  • protected则表示该方法将会被放置到动态符号表,对其他模块可见。但该符号对其所在模块是绑定的,即其他模块不可重载该符号。

  • internal,跟hidden相似。除非特别指定,否则意味着不能从模块调用该方法。

-fvisibility

既然说到了visibility,那顺带说一下这个flag,这个flag在调用gcc或者llvm时指定。表示编译时的对所有方法的默认visibility的选择(除非显式指定方法的visibility)。

-fvisibility=default|internal|hidden|protected

一般来说隐藏方法使用static就够了。但此attribute为大型工程项目提供了一种可能性,即可以使某些模块整体隐藏所有接口,只暴露特别指定的方法。

其他

此外gcc的编译器还可以像如下这样使用:

#pragma GCC visibility push(hidden)
void method1() {...}
void method2() {...}
...
#pragma GCC visibility pop

即表示在pushpop之间声明的所有方法,其可见性都按照指定的进行编译。

private_extern

这个关键字也有static相同的作用

总述

通过上述提供的几种手段,在一些复杂模块化的大中型项目中,我们可以更加灵活地对不同模块进行可行性的控制,能够更精细对项目进行模块化,并且减少符号被覆盖的风险。

llvm参考文档

还有一些有趣的attribute,以后再写

  • objc_root_class

  • objc_designated_initializer

  • naked

原作写于segmentfault 链接


canopus4u
618 声望50 粉丝